package edu.stanford.bmir.protege.web.client.ui.ontology.stkos.common.treepanel;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLAnnotation;
import org.semanticweb.owlapi.model.OWLAnnotationValueVisitor;
import org.semanticweb.owlapi.model.OWLAnonymousIndividual;
import org.semanticweb.owlapi.model.OWLLiteral;
import org.semanticweb.owlapi.vocab.OWLRDFVocabulary;

import com.google.common.collect.Lists;
import com.google.gwt.core.shared.GWT;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.gwtext.client.core.EventObject;
import com.gwtext.client.core.ExtElement;
import com.gwtext.client.data.Node;
import com.gwtext.client.widgets.tree.DefaultSelectionModel;
import com.gwtext.client.widgets.tree.TreeNode;
import com.gwtext.client.widgets.tree.TreePanel;
import com.gwtext.client.widgets.tree.event.DefaultSelectionModelListenerAdapter;
import com.gwtext.client.widgets.tree.event.TreePanelListenerAdapter;

import edu.stanford.bmir.protege.web.client.dispatch.DispatchServiceManager;
import edu.stanford.bmir.protege.web.client.dispatch.RenderableGetObjectResult;
import edu.stanford.bmir.protege.web.client.dispatch.actions.GetEntityAnnotationsAction;
import edu.stanford.bmir.protege.web.client.project.Project;
import edu.stanford.bmir.protege.web.client.rpc.OntologyServiceManager;
import edu.stanford.bmir.protege.web.client.rpc.data.EntityData;
import edu.stanford.bmir.protege.web.client.rpc.data.PropertyEntityData;
import edu.stanford.bmir.protege.web.client.rpc.data.PropertyType;
import edu.stanford.bmir.protege.web.client.rpc.data.Triple;
import edu.stanford.bmir.protege.web.client.rpc.data.ValueType;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.common.UtilConstants;
import edu.stanford.bmir.protege.web.client.ui.ontology.stkos.common.GWTExtUtil;
import edu.stanford.bmir.protege.web.client.ui.ontology.stkos.cutter.common.StkosCutterConstant;
import edu.stanford.bmir.protege.web.client.ui.util.UIUtil;
import edu.stanford.bmir.protege.web.shared.DataFactory;
import edu.stanford.bmir.protege.web.shared.PrimitiveType;
import edu.stanford.bmir.protege.web.shared.entity.OWLAnnotationPropertyData;
import edu.stanford.bmir.protege.web.shared.entity.OWLClassData;
import edu.stanford.bmir.protege.web.shared.entity.OWLDataPropertyData;
import edu.stanford.bmir.protege.web.shared.entity.OWLEntityData;
import edu.stanford.bmir.protege.web.shared.entity.OWLNamedIndividualData;
import edu.stanford.bmir.protege.web.shared.entity.OWLObjectPropertyData;
import edu.stanford.bmir.protege.web.shared.event.EventBusManager;
import edu.stanford.bmir.protege.web.shared.project.ProjectId;

/**
 * Abstract Stkos Tree Panel
 * <p>
 * The tree has default root node(not visible)!
 * </p>
 * 
 * @author LWS
 * 
 */
@SuppressWarnings("unchecked")
public abstract class AbstractStkosTreePanel extends TreePanel {

	class OWLAnnotationValueVisitorAdapter implements OWLAnnotationValueVisitor {
		EntityData entityData;

		public OWLAnnotationValueVisitorAdapter() {
		}

		public OWLAnnotationValueVisitorAdapter(EntityData entityData) {
			this.entityData = entityData;
		}

		@Override
		public void visit(OWLLiteral literal) {
			GWT.log("Entity[" + entityData + "] has a OWLLiteral(" + literal
					+ ") rdfs:comment annotation.");
		}

		@Override
		public void visit(OWLAnonymousIndividual individual) {
			GWT.log("Entity[" + entityData + "] has a OWLAnonymousIndividual("
					+ individual + ") rdfs:comment annotation.");
		}

		@Override
		public void visit(IRI iri) {
			GWT.log("Entity[" + entityData + "] has a IRI(" + iri
					+ ") rdfs:comment annotation.");
		}
	};

	final static String FLAG_MAPPING_NO = UtilConstants.FLAG_MAPPING_NO + ":";
	final static String FLAG_CUTTING = UtilConstants.FLAG_CUTTING + ":";
	final static String FLAG_ENRICHED = UtilConstants.FLAG_ENRICHED + ":";
	final static String FLAG_MERGED = UtilConstants.FLAG_MERGED + ":";
	final static String FLAG_FROM = UtilConstants.FLAG_FROM + ":";
	final static String FLAG_REF_PROJECT_DISPLAY_NAME = UtilConstants.FLAG_REF_PROJECT_DISPLAY_NAME
			+ ":";
	final static String FLAG_REF_PROJECT_ID = UtilConstants.FLAG_REF_PROJECT_ID
			+ ":";

	public final static String ROOTNODENAME = "Root";
	public final static String ROOTNODEID = "Root";

	final static EventBusManager manager = EventBusManager.getManager();

	private Project project;

	private DefaultSelectionModel selectionModel;

	protected AbstractStkosTreePanel(Project project) {
		checkNull(project);
		checkNull(project.getProjectId());
		this.project = project;
		initialize();
	}

	protected void checkNull(Object obj) {
		if (obj == null) {
			throw new NullPointerException("Required argument Can not be null.");
		}
	}

	public Project getProject() {
		return this.project;
	}

	@Override
	public DefaultSelectionModel getSelectionModel() {
		return this.selectionModel;
	}

	@Override
	protected void afterRender() {
	}

	private void initialize() {
		setAnimate(true);
		setAutoScroll(true);
		setRootVisible(false);

		TreeNode rootTreeNode = createRootNode();
		setRootNode(rootTreeNode);

		selectionModel = new DefaultSelectionModel();
		selectionModel
				.addSelectionModelListener(new DefaultSelectionModelListenerAdapter() {

					@Override
					public void onSelectionChange(
							final DefaultSelectionModel sm, final TreeNode node) {
						AbstractStkosTreePanel.this.onSelectionChange(sm, node);
					}
				});
		setSelectionModel(selectionModel);

		addListener(new TreePanelListenerAdapter() {
			@Override
			public void onExpandNode(final TreeNode node) {
				AbstractStkosTreePanel.this.onExpandNode(node);
			}

			@Override
			public void onContextMenu(final TreeNode node, final EventObject e) {
				AbstractStkosTreePanel.this.onContextMenu(node, e);
			}

			@Override
			public void onClick(final TreeNode node, final EventObject e) {
				AbstractStkosTreePanel.this.onClick(node, e);
			}

			@Override
			public void onDblClick(final TreeNode node, final EventObject e) {
				AbstractStkosTreePanel.this.onDblClick(node, e);
			}
		});

		registerProjectEventHandler();
	}

	protected TreeNode createRootNode() {
		TreeNode treeNode = new TreeNode(ROOTNODENAME);
		treeNode.setId(ROOTNODEID);
		treeNode.setLeaf(false);
		treeNode.setExpandable(true);
		return treeNode;
	}

	public void mask() {
		if (getEl() == null) {
			return;
		}
		getEl().mask("Loading...", true);
	}

	public void unmask() {
		if (getEl() == null) {
			return;
		}
		getEl().unmask();
	}

	public void scrollTreeNodeVisible(TreeNode treeNode) {
		if (treeNode == null) {
			return;
		}
		Element tel = treeNode.getUI().getEl();
		ExtElement treeBodyEl = getBody();

		int telt = tel.getOffsetHeight();
		int at = treeBodyEl.getDOM().getAbsoluteTop();
		int tat = tel.getAbsoluteTop() - at;
		int height = treeBodyEl.getHeight();
		int childHeight = treeBodyEl.getFirstChild().getOffsetHeight();
		if (height >= childHeight) {
			return;
		}
		int scrollTop = treeBodyEl.getScroll()[1];
		int maxScrollDis = childHeight - height;

		if ((tat + telt) > height) {
			scrollTop = scrollTop + tat + telt - height + height / 2;
		} else if (tat < 0) {
			scrollTop = scrollTop + tat - height / 2;
		} else {
			return;
		}

		if (scrollTop < 0) {
			scrollTop = 0;
		}
		if (scrollTop > maxScrollDis) {
			scrollTop = maxScrollDis;
		}
		treeBodyEl.setScrollTop(scrollTop);
	}

	protected void onClick(final TreeNode node, final EventObject e) {
		fireEvent(GWTExtUtil.EVENT_ONCLICK);
	}

	protected void onDblClick(final TreeNode node, final EventObject e) {
		fireEvent(GWTExtUtil.EVENT_ONDBLCLICK);
	}

	protected void onContextMenu(final TreeNode node, final EventObject e) {
		fireEvent(GWTExtUtil.EVENT_ONCONTEXTMENU);
		getSelectionModel().select(node);
	}

	protected void onSelectionChange(final DefaultSelectionModel sm,
			final TreeNode node) {
		fireEvent(GWTExtUtil.EVENT_ONSELECTIONCHANGE);
	}

	protected void onExpandNode(final TreeNode node) {
		fireEvent(GWTExtUtil.EVENT_ONEXPANDNODE);
		getChildren(node);
	}

	public void refreshTreeNode(final TreeNode node) {
		if (node == null) {
			GWT.log("Argument treeNode is null.");
			onRefresh();
			return;
		}
		final String id = node.getId();
		if (id == null) {
			GWT.log("Argument treeNode`s Id is null.");
			onRefresh();
			return;
		}
		final TreeNode parent = (TreeNode) node.getParentNode();
		if (parent == null) {
			GWT.log("Argument treeNode`s parentNode is null.");
			onRefresh();
			return;
		}
		boolean s = node.isSelected();
		boolean e = node.isExpanded();
		// The node`s parent is root node
		if (parent.getParentNode() == null) {
			onRefresh();
		} else {
			parent.collapse();
			for (Node child : parent.getChildNodes()) {
				child.remove();
			}
			parent.expand();
		}
		if (s) {
			Timer timer = new Timer() {
				int i = 0;

				@Override
				public void run() {
					if (i >= Integer.MAX_VALUE) {
						this.cancel();
						return;
					}
					TreeNode td = getNodeById(id);
					if (td != null) {
						td.select();
						this.cancel();
					}
					i++;
				}
			};
			timer.scheduleRepeating(25);
		}
		if (e) {
			Timer timer = new Timer() {
				int i = 0;

				@Override
				public void run() {
					if (i >= Integer.MAX_VALUE) {
						this.cancel();
						return;
					}
					TreeNode td = getNodeById(id);
					if (td != null) {
						td.expand();
						this.cancel();
					}
					i++;
				}
			};
			timer.scheduleRepeating(25);
		}
	}

	public void onRefresh() {
		TreeNode rootNode = getRootNode();
		if (rootNode == null) {
			return;
		}

		if (rootNode.getChildNodes() != null) {
			for (Node node : rootNode.getChildNodes()) {
				node.remove();
			}
		}

		setRootNodeChild();
	}

	protected TreeNode createTreeNode(EntityData entityData) {
		if (entityData == null) {
			return null;
		}
		TreeNode treeNode = new TreeNode(UIUtil.getDisplayText(entityData));
		treeNode.setId(entityData.getName());
		treeNode.setTooltip(entityData.getName());
		treeNode.setLeaf(true);
		treeNode.setExpandable(false);
		treeNode.setUserObject(entityData);

		return treeNode;
	}

	/**
	 * Add the entity rdfs:comment annotation mappingNo: to treeNode mark.
	 * 
	 * @param node
	 * @param entityData
	 * @see edu.stanford.bmir.protege.web.client.ui.ontology.stkos.mapper.common.StkosMapperConstant.STKOSMAPPERVALUEPREFIX
	 */
	protected void addAnnotationMappingNoNodeMark(final TreeNode node,
			final EntityData entityData, final String accordingProjectId) {
		if (node == null || entityData == null || accordingProjectId == null
				|| "".equals(accordingProjectId.trim())) {
			return;
		}
		String entityName = entityData.getName();
		final OWLAnnotationValueVisitor visitor = new OWLAnnotationValueVisitorAdapter(
				entityData) {
			@Override
			public void visit(OWLLiteral literal) {
				// The string like: mappingNo:5; refProjectName:agr;
				// refProjectID:32
				String mappingNo = literal.getLiteral().trim();
				int ind = mappingNo.indexOf(FLAG_MAPPING_NO);
				if (ind != -1) {
					String[] strs = mappingNo.split(";");
					// refProjectID
					try {
						String refProjectID = strs[2].replace(
								FLAG_REF_PROJECT_ID, "").trim();
						if (refProjectID.equals(accordingProjectId.trim())) {
							String str1 = strs[0].replace(FLAG_MAPPING_NO, "")
									.trim();
							int mappingNumber = Integer.parseInt(str1);
							node.setAttribute(FLAG_MAPPING_NO, mappingNumber);
							mappingNo = GWTExtUtil
									.createNodeMapperNumberLabel(mappingNumber);
							String text = node.getText();
							node.setText(text + mappingNo);

							/*
							 * String refProjectName = strs[1].replace(
							 * FLAG_REF_PROJECT_DISPLAY_NAME, "").trim();
							 */
						}
					} catch (Exception e) {
					}
				}
			}
		};

		AsyncCallback<List<OWLAnnotation>> cb = new AsyncCallback<List<OWLAnnotation>>() {
			@Override
			public void onFailure(Throwable caught) {
				GWT.log("Getting entity`s rdfs:comment annotation error.",
						caught);
			}

			@Override
			public void onSuccess(List<OWLAnnotation> result) {
				if (result == null || result.size() == 0) {
					return;
				}
				for (OWLAnnotation owlAnnotation : result) {
					owlAnnotation.getValue().accept(visitor);
				}
			}
		};
		getEntityComments(entityName, cb);
	}

	/**
	 * @deprecated Use
	 *             {@link #addAnnotationMappingNoNodeMark(TreeNode node,EntityData entityData)}
	 */
	@Deprecated
	protected void addAnnotationMappingNoNodeMark2(final TreeNode node,
			EntityData entityData) {
		AsyncCallback<List<Triple>> cb = new AsyncCallback<List<Triple>>() {
			@Override
			public void onFailure(Throwable caught) {
				GWT.log("Failure to get entity rdfs:comment annotations.",
						caught);
			}

			@Override
			public void onSuccess(List<Triple> result) {
				if (result == null || result.size() == 0) {
					return;
				}
				String flagmn = UtilConstants.FLAG_MAPPING_NO + ":";
				for (Triple triple : result) {
					try {
						// TODO The value like ~#en mappingNo:3
						String mappingNo = triple.getValue().getBrowserText()
								.trim();
						int ind = mappingNo.indexOf(flagmn);
						if (ind != -1) {
							mappingNo = mappingNo.substring(ind)
									.replace(flagmn, "").trim();

							if (GWTExtUtil.stringIsBlank(mappingNo)) {
								return;
							}

							int mappingNumber = Integer.parseInt(mappingNo);
							node.setAttribute(flagmn, mappingNo);
							mappingNo = GWTExtUtil
									.createNodeMapperNumberLabel(mappingNumber);

							String text = node.getText();

							node.setText(text + mappingNo);
						}
					} catch (Exception e) {
					}
				}
			}
		};

		getNodeRdfsCommentAnnotation(node, cb);
	}

	public Integer getNodeMapperNumber(TreeNode node) {
		Integer mapperNumber = null;
		try {
			mapperNumber = Integer.parseInt(node.getAttribute(FLAG_MAPPING_NO));
		} catch (Exception e) {
		}
		return mapperNumber;
	}

	/**
	 * Add the entity rdfs:comment annotation cuttingFlag: to treeNode mark.
	 * 
	 * @param node
	 * @param entityData
	 * @see edu.stanford.bmir.protege.web.client.rpc.stkosutil.common.UtilConstants
	 */
	protected void addAnnotationCuttingFlagNodeMark(final TreeNode node,
			final EntityData entityData) {
		String entityName = null;
		if (entityData != null) {
			entityName = entityData.getName();
		}
		final OWLAnnotationValueVisitor visitor = new OWLAnnotationValueVisitorAdapter(
				entityData) {
			@Override
			public void visit(OWLLiteral literal) {
				// Find the string like: cuttingFlag: Y
				String cuttingFlag = literal.getLiteral().trim();
				int ind = cuttingFlag.indexOf(FLAG_CUTTING);
				if (ind != -1) {
					cuttingFlag = cuttingFlag.substring(ind)
							.replace(FLAG_CUTTING, "").trim();

					if ("Y".equals(cuttingFlag)) {
						node.setAttribute(FLAG_CUTTING, cuttingFlag);
						node.setAttribute(StkosCutterConstant.DEFAULTICONCLS,
								node.getAttribute("iconCls"));
						GWTExtUtil.setTreeNodeIconCls(node,
								StkosCutterConstant.CUTTER_ICONCLS);
					}
				}
			}
		};

		AsyncCallback<List<OWLAnnotation>> cb = new AsyncCallback<List<OWLAnnotation>>() {
			@Override
			public void onFailure(Throwable caught) {
				GWT.log("Getting entity`s rdfs:comment annotation error.",
						caught);
			}

			@Override
			public void onSuccess(List<OWLAnnotation> result) {
				if (result == null || result.size() == 0) {
					return;
				}
				for (OWLAnnotation owlAnnotation : result) {
					owlAnnotation.getValue().accept(visitor);
				}
			}
		};
		getEntityComments(entityName, cb);
	}

	/**
	 * @deprecated Use
	 *             {@link #addAnnotationCuttingFlagNodeMark(TreeNode node,EntityData entityData)}
	 */
	@Deprecated
	protected void addAnnotationCuttingFlagNodeMark2(final TreeNode node,
			final EntityData entityData) {
		AsyncCallback<List<Triple>> cb = new AsyncCallback<List<Triple>>() {
			@Override
			public void onFailure(Throwable caught) {
				GWT.log("Failure to get entity rdfs:comment annotations.",
						caught);
			}

			@Override
			public void onSuccess(List<Triple> result) {
				if (result == null || result.size() == 0) {
					GWT.log("The rdfs:comment annotation of entity["
							+ entityData + "] is empty. Callback result info: "
							+ result);
					return;
				}
				String flagc = UtilConstants.FLAG_CUTTING + ":";
				for (Triple triple : result) {
					try {
						// TODO The value like ~#en cuttingFlag:Y
						String cuttingFlag = triple.getValue().getBrowserText()
								.trim();
						int ind = cuttingFlag.indexOf(flagc);
						if (ind != -1) {
							cuttingFlag = cuttingFlag.substring(ind)
									.replace(flagc, "").trim();

							if ("Y".equals(cuttingFlag)) {
								node.setAttribute(flagc, cuttingFlag);
								node.setAttribute(
										StkosCutterConstant.DEFAULTICONCLS,
										node.getAttribute("iconCls"));
								GWTExtUtil.setTreeNodeIconCls(node,
										StkosCutterConstant.CUTTER_ICONCLS);
							}
						}
					} catch (Exception e) {
					}
				}
			}
		};
		getNodeRdfsCommentAnnotation(node, cb);
	}

	protected String getNodeCutterValue(TreeNode node) {
		return node.getAttribute(FLAG_CUTTING);
	}

	/**
	 * Add the entity rdfs:comment annotation enrichedFlag: to treeNode mark.
	 * 
	 * @param node
	 * @param entityData
	 * @see edu.stanford.bmir.protege.web.client.rpc.stkosutil.common.UtilConstants
	 */
	protected void addAnnotationEnrichedFlagNodeMark(final TreeNode node,
			final EntityData entityData) {
		String entityName = null;
		if (entityData != null) {
			entityName = entityData.getName();
		}
		final OWLAnnotationValueVisitor visitor = new OWLAnnotationValueVisitorAdapter(
				entityData) {
			@Override
			public void visit(OWLLiteral literal) {
				// Find the string like: enrichedFlag: Y; from: CRTC Thesaurus
				String enrichedFlag = literal.getLiteral().trim();
				int ind = enrichedFlag.indexOf(FLAG_ENRICHED);
				if (ind != -1) {
					enrichedFlag = enrichedFlag.substring(ind).trim();
					String[] values = enrichedFlag.split(";");
					if (values != null && values.length > 0) {
						String enrichedFlagStr = null, fromStr = null;
						for (int i = 0; i < values.length; i++) {
							if (values[i] != null) {
								if (values[i].contains(FLAG_ENRICHED)) {
									enrichedFlagStr = values[i].trim();
								}
								if (values[i].contains(FLAG_FROM)) {
									fromStr = values[i].trim();
								}
							}
						}
						// Getting the enrichedFlag: value.
						if (enrichedFlagStr != null) {
							String enrichedFlagValue = enrichedFlagStr
									.substring(
											enrichedFlagStr
													.indexOf(FLAG_ENRICHED))
									.replace(FLAG_ENRICHED, "").trim();
							if ("Y".equalsIgnoreCase(enrichedFlagValue)) {
								node.setAttribute(FLAG_ENRICHED,
										enrichedFlagValue);
								String bText = entityData.getBrowserText() == null ? ""
										: entityData.getBrowserText();
								String text = node.getText();
								text = text.replace(bText, GWTExtUtil
										.createNodeEnrichedFlagLabel(bText));
								node.setText(text);
							}
						}
						// Getting the from: value.
						if (fromStr != null) {
							String enricherFormValue = fromStr
									.substring(fromStr.indexOf(FLAG_FROM))
									.replace(FLAG_FROM, "").trim();
							node.setAttribute(FLAG_FROM, enricherFormValue);
						}
					}
				}
			}
		};

		AsyncCallback<List<OWLAnnotation>> cb = new AsyncCallback<List<OWLAnnotation>>() {
			@Override
			public void onFailure(Throwable caught) {
				GWT.log("Getting entity`s rdfs:comment annotation error.",
						caught);
			}

			@Override
			public void onSuccess(List<OWLAnnotation> result) {
				if (result == null || result.size() == 0) {
					return;
				}
				for (OWLAnnotation owlAnnotation : result) {
					owlAnnotation.getValue().accept(visitor);
				}
			}
		};
		getEntityComments(entityName, cb);
	}

	/**
	 * @deprecated Use
	 *             {@link #addAnnotationEnrichedFlagNodeMark(TreeNode node,EntityData entityData)}
	 */
	@Deprecated
	protected void addAnnotationEnrichedFlagNodeMark2(final TreeNode node,
			final EntityData entityData) {
		AsyncCallback<List<Triple>> cb = new AsyncCallback<List<Triple>>() {
			@Override
			public void onFailure(Throwable caught) {
				GWT.log("Failure to get entity rdfs:comment annotations.",
						caught);
			}

			@Override
			public void onSuccess(List<Triple> result) {
				if (result == null || result.size() == 0) {
					return;
				}
				for (Triple triple : result) {
					try {
						String f1 = UtilConstants.FLAG_ENRICHED + ":";
						String f2 = UtilConstants.FLAG_FROM + ":";
						// TODO The value like ~#en enrichedFlag: Y; from:
						// Thesaurus Ethics in the Life Sciences
						String enrichedFlag = triple.getValue()
								.getBrowserText().trim();
						if (enrichedFlag.contains(f1)) {
							String[] values = enrichedFlag.split(";");
							if (values != null && values.length > 0) {
								String enrichedFlagStr = null, fromStr = null;
								for (int i = 0; i < values.length; i++) {
									if (values[i] != null) {
										if (values[i].contains(f1)) {
											enrichedFlagStr = values[i].trim();
										}
										if (values[i].contains(f2)) {
											fromStr = values[i].trim();
										}
									}
								}
								if (enrichedFlagStr != null) {
									String enrichedFlagValue = enrichedFlagStr
											.substring(
													enrichedFlagStr.indexOf(f1))
											.replace(f1, "").trim();
									if ("Y".equalsIgnoreCase(enrichedFlagValue)) {
										node.setAttribute(f1, enrichedFlagValue);
										String bText = entityData
												.getBrowserText() == null ? ""
												: entityData.getBrowserText();
										String text = node.getText();
										text = text
												.replace(
														bText,
														GWTExtUtil
																.createNodeEnrichedFlagLabel(bText));
										node.setText(text);
									}
								}
								if (fromStr != null) {
									String enricherFormValue = fromStr
											.substring(fromStr.indexOf(f2))
											.replace(f2, "").trim();
									node.setAttribute(f2, enricherFormValue);
								}
							}
						}
					} catch (Exception e) {
					}
				}
			}

		};
		getNodeRdfsCommentAnnotation(node, cb);
	}

	protected String getNodeEnricherValue(TreeNode node) {
		return node.getAttribute(FLAG_ENRICHED);
	}

	/**
	 * Add the entity rdfs:comment annotation mergedFlag: to treeNode mark.
	 * 
	 * @param node
	 * @param entityData
	 * @see edu.stanford.bmir.protege.web.client.rpc.stkosutil.common.UtilConstants
	 */
	protected void addAnnotationMergedFlagNodeMark(final TreeNode node,
			final EntityData entityData) {
		String entityName = null;
		if (entityData != null) {
			entityName = entityData.getName();
		}
		final OWLAnnotationValueVisitor visitor = new OWLAnnotationValueVisitorAdapter(
				entityData) {
			@Override
			public void visit(OWLLiteral literal) {
				// Find the string like: mergedFlag: Y; from: ProjectId{55}
				String mergedFlag = literal.getLiteral().trim();
				int ind = mergedFlag.indexOf(FLAG_MERGED);
				if (ind != -1) {
					mergedFlag = mergedFlag.substring(ind).trim();
					String[] values = mergedFlag.split(";");
					if (values != null && values.length > 0) {
						String enrichedFlagStr = null, fromStr = null;
						for (int i = 0; i < values.length; i++) {
							if (values[i] != null) {
								if (values[i].contains(FLAG_MERGED)) {
									enrichedFlagStr = values[i].trim();
								}
								if (values[i].contains(FLAG_FROM)) {
									fromStr = values[i].trim();
								}
							}
						}
						// Getting the mergedFlag: value.
						if (enrichedFlagStr != null) {
							String enrichedFlagValue = enrichedFlagStr
									.substring(
											enrichedFlagStr
													.indexOf(FLAG_MERGED))
									.replace(FLAG_MERGED, "").trim();
							if ("Y".equalsIgnoreCase(enrichedFlagValue)) {
								node.setAttribute(FLAG_MERGED,
										enrichedFlagValue);
								String bText = entityData.getBrowserText() == null ? ""
										: entityData.getBrowserText();
								String text = node.getText();
								text = text.replace(bText, GWTExtUtil
										.createNodeEnrichedFlagLabel(bText));
								node.setText(text);
							}
						}
						// Getting the from: value.
						if (fromStr != null) {
							String enricherFormValue = fromStr
									.substring(fromStr.indexOf(FLAG_FROM))
									.replace(FLAG_FROM, "").trim();
							node.setAttribute(FLAG_FROM, enricherFormValue);
						}
					}
				}
			}
		};

		AsyncCallback<List<OWLAnnotation>> cb = new AsyncCallback<List<OWLAnnotation>>() {
			@Override
			public void onFailure(Throwable caught) {
				GWT.log("Getting entity`s rdfs:comment annotation error.",
						caught);
			}

			@Override
			public void onSuccess(List<OWLAnnotation> result) {
				if (result == null || result.size() == 0) {
					return;
				}
				for (OWLAnnotation owlAnnotation : result) {
					owlAnnotation.getValue().accept(visitor);
				}
			}
		};
		getEntityComments(entityName, cb);
	}

	/**
	 * @deprecated Use
	 *             {@link #addAnnotationMergedFlagNodeMark(TreeNode node,EntityData entityData)}
	 */
	@Deprecated
	protected void addAnnotationMergedFlagNodeMark2(final TreeNode node,
			final EntityData entityData) {
		AsyncCallback<List<Triple>> cb = new AsyncCallback<List<Triple>>() {
			@Override
			public void onFailure(Throwable caught) {
				GWT.log("Failure to get entity rdfs:comment annotations.",
						caught);
			}

			@Override
			public void onSuccess(List<Triple> result) {
				if (result == null || result.size() == 0) {
					return;
				}
				String f1 = UtilConstants.FLAG_MERGED + ":";
				String f2 = UtilConstants.FLAG_FROM + ":";
				for (Triple triple : result) {
					try {
						// TODO The value like ~#en mergedFlag: Y; from:
						// ProjectId{5bc7c742-7952-4c09-8c39-77330401aa3f}
						String mergedFlag = triple.getValue().toString();
						if (mergedFlag.contains(f1)) {
							String[] values = mergedFlag.split(";");
							if (values != null && values.length > 0) {
								String mergedFlagStr = null, fromStr = null;
								for (int i = 0; i < values.length; i++) {
									if (values[i] != null) {
										if (values[i].contains(f1)) {
											mergedFlagStr = values[i].trim();
										}
										if (values[i].contains(f2)) {
											fromStr = values[i].trim();
										}
									}
								}
								if (mergedFlagStr != null) {
									String mergedFlagValue = mergedFlagStr
											.substring(
													mergedFlagStr.indexOf(f1))
											.replace(f1, "").trim();
									if ("Y".equalsIgnoreCase(mergedFlagValue)) {
										node.setAttribute(f1, mergedFlagValue);
										String bText = entityData
												.getBrowserText() == null ? ""
												: entityData.getBrowserText();
										String text = node.getText();
										text = text
												.replace(
														bText,
														GWTExtUtil
																.createNodeMergedFlagLabel(bText));
										node.setText(text);
									}
								}
								if (fromStr != null) {
									String mergedFormValue = fromStr
											.substring(fromStr.indexOf(f2))
											.replace(f2, "").trim();
									node.setAttribute(f2, mergedFormValue);
								}
							}
						}
					} catch (Exception e) {
					}
				}
			}
		};
		getNodeRdfsCommentAnnotation(node, cb);
	}

	protected String getNodeMergedValue(TreeNode node) {
		return node.getAttribute(FLAG_MERGED);
	}

	protected String getNodeFromValue(TreeNode node) {
		return node.getAttribute(FLAG_FROM);
	}

	/**
	 * Getting entity`s all annotations.
	 * 
	 * @param entityName
	 * @param callback
	 */
	protected void getEntityAnnotations(
			final String entityName,
			final AsyncCallback<RenderableGetObjectResult<Set<OWLAnnotation>>> callback) {
		if (callback == null) {
			GWT.log("The required argument callBack function is null.");
			return;
		}
		if (entityName == null) {
			Throwable throwable = new Throwable(
					"The required argument entityName is null.");
			callback.onFailure(throwable);
			return;
		}
		IRI entityIRI = IRI.create(entityName);
		ProjectId projectId = getProject().getProjectId();
		GetEntityAnnotationsAction action = new GetEntityAnnotationsAction(
				entityIRI, projectId);
		DispatchServiceManager.get().execute(action, callback);
	}

	/**
	 * Getting entity`s rdfs:comment annotations.
	 * 
	 * @param entityName
	 * @param cb
	 */
	protected void getEntityComments(final String entityName,
			final AsyncCallback<List<OWLAnnotation>> cb) {
		if (cb == null) {
			GWT.log("The required argument callBack function is null.");
			return;
		}
		AsyncCallback<RenderableGetObjectResult<Set<OWLAnnotation>>> callback = new AsyncCallback<RenderableGetObjectResult<Set<OWLAnnotation>>>() {
			@Override
			public void onFailure(Throwable caught) {
				cb.onFailure(caught);
			}

			@Override
			public void onSuccess(
					RenderableGetObjectResult<Set<OWLAnnotation>> result) {
				if (result == null || result.getObject() == null) {
					cb.onSuccess(null);
					return;
				}
				List<OWLAnnotation> owlAnnotations = new ArrayList<OWLAnnotation>();
				for (OWLAnnotation data : result.getObject()) {
					if (data.getProperty().isComment()) {
						owlAnnotations.add(data);
					}
				}
				cb.onSuccess(owlAnnotations);
			}
		};
		getEntityAnnotations(entityName, callback);
	}

	/**
	 * Getting the entity rdfs:comment annotation. (some entity`s rdfs:comment
	 * can not find.)
	 * 
	 * @param node
	 * @param cb
	 * @deprecated Use
	 *             {@link #getEntityComments(TreeNode node,EntityData entityData)}
	 */
	@Deprecated
	protected void getNodeRdfsCommentAnnotation(final TreeNode node,
			final AsyncCallback<List<Triple>> cb) {
		if (cb == null) {
			GWT.log("The argument callBack function is null.");
			return;
		}
		if (node == null) {
			GWT.log("The argument treeNode is null.");
			cb.onSuccess(null);
			return;
		}
		if (node.getUserObject() == null) {
			GWT.log("The entityData is null.");
			cb.onSuccess(null);
			return;
		}
		String entityName = null;
		if (node.getUserObject() instanceof OWLEntityData) {
			entityName = ((OWLEntityData) node.getUserObject()).getEntity()
					.getIRI().toString();
		} else if (node.getUserObject() instanceof EntityData) {
			entityName = ((EntityData) node.getUserObject()).getName();
		} else {
			GWT.log("Can not get the entityData`s name.Details: "
					+ node.getUserObject());
		}
		if (entityName == null) {
			GWT.log("The entityName is null.");
			cb.onSuccess(null);
			return;
		}
		List<String> entities = Lists.newArrayList(entityName);
		List<String> properties = Lists
				.newArrayList(OWLRDFVocabulary.RDFS_COMMENT.getIRI().toString());
		OntologyServiceManager.getInstance().getEntityTriples(
				project.getProjectId(), entities, properties, cb);
	}

	public OWLEntityData getSelectedOWLEntityData() {
		return toOWLEntityData(getSelectedTreeNode());
	}

	public TreeNode getSelectedTreeNode() {
		TreeNode treeNode = null;
		try {
			treeNode = selectionModel.getSelectedNode();
		} catch (Exception e) {
			GWT.log("Getting selected treeNode error.", e);
		}
		return treeNode;
	}

	public OWLEntityData toOWLEntityData(TreeNode treeNode) {
		OWLEntityData owlEntityData = null;
		try {
			Object obj = treeNode.getUserObject();
			if (obj == null) {
			} else if (obj instanceof EntityData) {
				EntityData entityData = (EntityData) obj;
				if (entityData instanceof PropertyEntityData) {
					PropertyEntityData propertyEntityData = (PropertyEntityData) entityData;
					PropertyType propertyType = propertyEntityData
							.getPropertyType();
					if (propertyType != null) {
						switch (propertyType) {
						case OBJECT:
							owlEntityData = new OWLObjectPropertyData(
									DataFactory.getOWLObjectProperty(entityData
											.getName()),
									entityData.getBrowserText());
							break;
						case DATATYPE:
							owlEntityData = new OWLDataPropertyData(
									DataFactory.getOWLDataProperty(entityData
											.getName()),
									entityData.getBrowserText());
							break;
						case ANNOTATION:
							owlEntityData = new OWLAnnotationPropertyData(
									DataFactory.getOWLAnnotationProperty(entityData
											.getName()),
									entityData.getBrowserText());
							break;
						default:
							break;
						}
					}
				} else if (entityData.getValueType() == ValueType.Cls) {
					owlEntityData = new OWLClassData(
							DataFactory.getOWLClass(entityData.getName()),
							entityData.getBrowserText());
				} else if (entityData.getValueType() == ValueType.Instance) {
					owlEntityData = new OWLNamedIndividualData(
							DataFactory.getOWLNamedIndividual(entityData
									.getName()), entityData.getBrowserText());
				} else if (entityData.getValueType() == ValueType.Property) {
				} else {
				}
			} else if (obj instanceof OWLEntityData) {
				owlEntityData = (OWLEntityData) obj;
			} else {
			}
		} catch (Exception e) {
			GWT.log("Convert to OWLEntityData error.", e);
		}
		return owlEntityData;
	}

	protected EntityData toEntityData(OWLEntityData owlEntityData) {
		EntityData entityData = null;
		if (owlEntityData != null) {
			String name = null, browserText = null;
			try {
				name = owlEntityData.getEntity().getIRI().toString();
				browserText = owlEntityData.getBrowserText();
			} catch (Exception e) {
				GWT.log("Convert OWLEntityData to EntityData error.", e);
			}
			if (name != null && browserText != null) {
				if (PrimitiveType.ANNOTATION_PROPERTY.equals(owlEntityData
						.getType())) {
					PropertyEntityData propertyEntityData = new PropertyEntityData(
							name, browserText, null);
					propertyEntityData.setPropertyType(PropertyType.ANNOTATION);
					entityData = propertyEntityData;
				} else if (PrimitiveType.OBJECT_PROPERTY.equals(owlEntityData
						.getType())) {
					PropertyEntityData propertyEntityData = new PropertyEntityData(
							name, browserText, null);
					propertyEntityData.setPropertyType(PropertyType.OBJECT);
					entityData = propertyEntityData;
				} else if (PrimitiveType.DATA_PROPERTY.equals(owlEntityData
						.getType())) {
					PropertyEntityData propertyEntityData = new PropertyEntityData(
							name, browserText, null);
					propertyEntityData.setPropertyType(PropertyType.DATATYPE);
					entityData = propertyEntityData;
				} else if (PrimitiveType.CLASS.equals(owlEntityData.getType())) {
					entityData = new EntityData(name, browserText);
					entityData.setValueType(ValueType.Cls);
				} else if (PrimitiveType.NAMED_INDIVIDUAL.equals(owlEntityData
						.getType())) {
					entityData = new EntityData(name, browserText);
					entityData.setValueType(ValueType.Instance);
				}
			}
		}
		return entityData;
	}

	/**
	 * You should do like this: </br> <code>
	 * 	TreeNode[] rootNodeChild = {};
	 * 	for(TreeNode treeNode : rootNodeChild){ 
	 * 		getRootNode().appendChild(treeNode); 
	 * 	}
	 * </code> </br>
	 */
	protected abstract void setRootNodeChild();

	/**
	 * Get the children of node.
	 * 
	 * @param node
	 */
	protected abstract void getChildren(final TreeNode node);

	/**
	 * register some project events handler to this treepanel.
	 */
	protected abstract void registerProjectEventHandler();
}
